#include <condefs.h>

#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dir.h>

  #define COMP_16  0xF0
  #define RLE_FLAG 0xF1
  #define COMP_24  0xF2
//  #define RLE_12C2 0xF3
//  #define DATA_ORA 0xF4
//  #define RLE_FLAG 0xF5
//  #define RLE_FLAG 0xF6
  #define CTR_FLAG 0xF7
  #define RLE_NULL 0xF8

  typedef unsigned long  LONG;
  typedef unsigned short WORD;
  typedef unsigned char  BYTE;

  struct _TMENU
  { //
    char buf[256];
    char tag[256];
    char rfile[MAXPATH];
    char dfile[MAXPATH];
    LONG point;
    BYTE col;
    BYTE row;
    BYTE width;
    BYTE height;
    LONG Comp;
    LONG ofStart;
    LONG ofEnd;
    LONG rdStart;
    LONG rdEnd;
  } menu;

  struct _RLE
  { //
    LONG lof;
    LONG cpPosi;
    LONG dcPosi;
    BYTE ram[0x10000];
    WORD rom[0x10000];
    //
    WORD data;
    BYTE count;
  } rle;

  FILE *rf,
       *df,
       *tf,
       *ef;

  char efile[MAXPATH];

  LONG FileSize( FILE *tf );
  int  LoadTagData( FILE *tf );

//-------------------------------//
//                               //
//-------------------------------//
int  main( int argc, char *argv[] )
{
  int  c     = 0;

  // Make sure we have an argument to read in
  if ( argc > 1 )
  { //
    tf = fopen( argv[1], "rt" );
    if ( !tf ){
      printf("Fatal Error: Could not open data file." );
      return -1;
    }

    strcpy( efile, argv[0] );
    c = strlen( efile) -1;
    while( efile[c] != '\\' && efile[c] != '/' ) c--;
    c++;
    //
    strcpy( &efile[c], "MenuErr.log" );
    ef = fopen( efile, "wt" );
    if ( !ef ){
      printf("Error: Could not open Source file..." );
      fcloseall( );
      return -1;
    }

    //
    menu.rdStart =
    menu.rdEnd   = 0;

    //
    while( !LoadTagData( tf ) )
    { // Process data
      rf = fopen( menu.rfile, "r+b" );
      df = fopen( menu.dfile, "r+b" );
      //
      if ( !rf ){
        fprintf( ef, "\nFatal Error: Could not open Output file: \"%s\"\n", menu.rfile );
        fcloseall( );
        return  - 1;
      } else
        fclose( rf );

      //
      if ( !df ){
        fprintf( ef, "\nFatal Error: Could not open Input file: \"%s\"\n", menu.dfile );
        fclose( df );
        fclose( rf );
        continue;
//        return  - 1;
      }

      // Try to recompress the thing now...
      rle.cpPosi = 0;
      rle.dcPosi = 0;
      rle.lof    = FileSize( df );
      //
      memset( rle.ram, 0, 0x10000 );
      memset( rle.rom, 0, 0x10000 );

      // Get pass the size byes
      menu.height = fgetc( df );
      menu.width  = fgetc( df );
      //
      fread( (BYTE *)rle.rom, 1, rle.lof-2, df );
      fclose( df );
      df = NULL;
      // Data IS in WORD format
      rle.lof  -=2;
      rle.lof >>= 1;

      // If we do NO compression
      if ( !menu.Comp )
      { //
        rle.data  = rle.rom[ rle.cpPosi ];      
        while( rle.cpPosi < rle.lof )
        { // check for New attribute
          if ( (rle.data & 0xFF00) != 0x2200 ) {
            rle.ram[ rle.dcPosi++ ] = 0xF4;
            rle.ram[ rle.dcPosi++ ] = (rle.data & 0xFF);
            rle.ram[ rle.dcPosi++ ] = (rle.data >> 8) & 0xFF;
            rle.data                = rle.rom[ ++rle.cpPosi ];
          } else {
            rle.ram[ rle.dcPosi++ ] = (rle.data & 0xFF);
            rle.data                = rle.rom[ ++rle.cpPosi ];
          }
        }// WEND
      }
      else
      {
        //------------------------------------//
        // This will loop until we are able   //
        // to use Compression =], if possible //
        //------------------------------------//
        while( rle.cpPosi < rle.lof )
        { //
          rle.count = 0;
          rle.data  = rle.rom[ rle.cpPosi ];
          //
          _Universal:
          if ( (rle.cpPosi + 2) < rle.lof && ( rle.rom[ rle.cpPosi + 1] == rle.data ) && ( rle.rom[ rle.cpPosi + 2] == rle.data ) )
          { //--------------------//
            // Do the RLE testing //
            //--------------------//
            while( ( rle.rom[ rle.cpPosi + rle.count ] == rle.data ) && ( (rle.cpPosi + rle.count) < rle.lof ) && rle.count < 0xFF )
              rle.count++;

            // Store Compressed data

            if ( (rle.data & 0xFF) == 0x01 )
            { // When it is $00
              rle.ram[ rle.dcPosi++ ] = RLE_NULL;
              rle.ram[ rle.dcPosi++ ] = rle.count;
              rle.cpPosi             += rle.count;
            }
            else
            { // all else
              rle.ram[ rle.dcPosi++ ] = RLE_FLAG;
              rle.ram[ rle.dcPosi++ ] = rle.count;
              rle.ram[ rle.dcPosi++ ] = rle.data & 0xFF;
              rle.cpPosi             += rle.count;
            }
          }
          else
          { //
            while( (rle.cpPosi < rle.lof) && ( (rle.rom[ rle.cpPosi + 1] != rle.data) || (rle.rom[ rle.cpPosi + 2] != rle.data) ) )
            { // check for New attribute
              if ( (rle.data & 0xFF00) != 0x2200 ) {
                rle.ram[ rle.dcPosi++ ] = 0xF4;
                rle.ram[ rle.dcPosi++ ] = (rle.data & 0xFF);
                rle.ram[ rle.dcPosi++ ] = (rle.data >> 8) & 0xFF;
                rle.data                = rle.rom[ ++rle.cpPosi ];
              } else {
                rle.ram[ rle.dcPosi++ ] = (rle.data & 0xFF);
                rle.data                = rle.rom[ ++rle.cpPosi ];
              }
            }// WEND

            if ( (rle.cpPosi < rle.lof) && !menu.Comp ) goto _Universal;
          }// END IF
        } // WEND - rle.cpPosi

      } // END IF - Use compression or not


      // Check to see if we re-align the data
      if ( menu.rdStart ){
        menu.ofStart = menu.rdStart + 4;
        menu.ofEnd   = menu.rdEnd;
      }

      //--------------------------------------//
      // Calculate the size and deternmine if //
      // we can store the data in the space   //
      //--------------------------------------//
      if ( rle.dcPosi > (menu.ofEnd - menu.ofStart) )
      { // Too large
        fprintf(ef, "%s is %d BYTES larger than %d.\n", menu.dfile, rle.dcPosi - (menu.ofEnd - menu.ofStart), rle.dcPosi );
      }
      else
      { //
        fprintf( ef,
                 "%s compressed successfully with %d BYTE(S) to spare.\n", menu.dfile,
                 (menu.ofEnd - menu.ofStart) - rle.dcPosi
               );
        //
        rf = fopen( menu.rfile, "rb+" );
        // Store
        if ( rf ){
          rle.lof = FileSize( rf );
          // Check to see if ROM was expanded already!
          if ( rle.lof < menu.rdStart ){
            printf("Fatal Error: Redirection Position is Greater than Allowed position!" );
            fcloseall( );
            return -1;
          }
          // Store the NEW or Old pointer
          fseek( rf, menu.point, SEEK_SET );
          //
          fputc(( ((menu.ofStart-4) | 0x8000) >> 0 ) & 0xFF, rf );
          fputc(( ((menu.ofStart-4) | 0x8000) >> 8 ) & 0xFF, rf );
          //
          fseek( rf, menu.ofStart - 4, SEEK_SET );
          // Store NEW ( if any ) Column, Row, Width, and Height
          fputc( menu.col, rf );
          fputc( menu.row, rf );
          fputc( menu.width, rf );
          fputc( menu.height, rf );
          fwrite( rle.ram, 1, rle.dcPosi, rf );
          //
          fclose( rf );

          if ( menu.rdStart )
            menu.rdStart = (menu.ofStart + rle.dcPosi);
          //
        }
      }// END IF

    }// WEND - LoadTagData

  }// END IF - argc

  fcloseall( );
  
  return 0;
}


//----------------------//
//                      //
//----------------------//
LONG FileSize( FILE *tf )
{
  LONG FSize,
       tmPosi;

  if ( !tf ) return - 1;
  //
  tmPosi = ftell( tf );
  fseek( tf, 0, SEEK_END );
  FSize = ftell( tf );
  fseek( tf, tmPosi, SEEK_SET );

  return FSize;
}



//----------------------//
//                      //
//----------------------//
int  LoadTagData( FILE *tf )
{
  //
  while( fgets(menu.buf, 255, tf) )
  { // Find a TAG string
    if ( !strncmpi( menu.buf, ".REALIGN", 8 ) )
    { //
      sscanf( menu.buf, "%s %X %X", &menu.buf[128], &menu.rdStart, &menu.rdEnd );
    }
    else
    if ( !strncmpi( menu.buf, ".MENU", 5 ) )
    { // Load te structure with info!
      sscanf( menu.buf,
              "%s %s %s %X %d %d %d %d %X %X %X",
              &menu.tag,
              &menu.rfile,
              &menu.dfile,
              &menu.point,
              &menu.col,
              &menu.row,
              &menu.width,
              &menu.height,
              &menu.ofStart,
              &menu.ofEnd,
              &menu.Comp
            );
       //
       if ( (long)menu.Comp == -1 )
         menu.Comp = 0;
       //
       return 0;
     }
  }

  return -1;
}
